/*
 * CommandThread.h
 *
 *  Created on: 2017年11月8日
 *      Author: zhengboyuan
 */

#ifndef COMMANDTHREAD_H_
#define COMMANDTHREAD_H_

#include "BasicType.h"
#include "TThread.h"
#include "TEvent.h"
#include "TCriticalSection.h"
#include <queue>
#include <string>

namespace util
{

struct Param
{
	enum Type
	{
		kBool,
		kInt,
		kLong,
		kFloat,
		kDouble,
		kString,
		kPointer,
	};

	Type type;

	union Value
	{
		bool b;
		int i32;
		int64_t i64;
		float f;
		double d;
		void* ptr;
	} value;

	std::string      str;

	Param();
	explicit Param(bool value);
	explicit Param(int32_t value);
	explicit Param(int64_t value);
	explicit Param(float value);
	explicit Param(double value);
	explicit Param(const char* value);
	explicit Param(const std::string& value);
	explicit Param(void* value);

	bool toBool() const;
	int  toInt() const;
	int64_t toLong() const;
	float toFloat() const;
	double toDouble() const;
	std::string toString() const;
	void* toPtr() const;

};

typedef std::deque< Param >	Paramlist;


class Command
{
public:
	static const int MAX_PARAMS = 4;

	enum CommandType
	{
		kQuit = -1,
		kNone = 0,
		kUser = 100
	};

	static Param s_param;

public:
	int type;
	Paramlist params;

	explicit Command(int t=kNone):
		type(t),
		params()
	{
	}

	Command(int t, const Param& param):
		type(t),
		params()
	{
		add(param);
	}

	Command(int t, const Param& param, const Param& p2):
		type(t),
		params()
	{
		add(param);
		add(p2);
	}

	void add(const Param& param)
	{
		params.push_back(param);
	}

	void clear()
	{
		params.clear();
		type = kNone;
	}

	size_t size() const
	{
		return params.size();
	}

	Param& operator [] (size_t idx)
	{
		if (idx >= params.size())
		{
			return s_param;
		}
		return params[idx];
	}

	const Param& operator [] (size_t idx) const
	{
		if (idx >= params.size())
		{
			return s_param;
		}
		return params[idx];
	}

};


class CommandThread : public comn::Thread
{
public:

	typedef std::queue< Command >	CommandQueue;

	enum Constant
	{
		IDLE_DURATION = 1000 * 10,	/// millisecond
	};

public:
	CommandThread();
	virtual ~CommandThread();

	void postCommand(const Command& cmd);

	void postCommand(int cmdType);

	template < class T >
	void postCommand(int cmdType, T t)
	{
		Param param(t);
		Command cmd(cmdType, param);
		postCommand(cmd);
	}

	template < class T , class E >
	void postCommand(int cmdType, T t, E e)
	{
		Param param(t);
		Param ext(e);
		Command cmd(cmdType, param, ext);
		postCommand(cmd);
	}

	void postQuit();


	bool getCommand(Command& cmd);

	void clearQueue();

	void postEvent();

	bool timedwait(int ms);

	void stop();

protected:

	virtual void onCommand(Command& cmd) =0;
	virtual void onIdle();

	bool fetchAndHandle();

protected:
	virtual int run();
	virtual void doStop();

protected:
	comn::CriticalSection	m_csCmd;
	comn::Event		m_eventCmd;
	CommandQueue	m_cmdQueue;

};


} /* namespace util */

#endif /* COMMANDTHREAD_H_ */
